Skip to content

docs: fill gaps surfaced by developer feedback#563

Open
localden wants to merge 8 commits intomainfrom
docs/fill-gaps-from-feedback
Open

docs: fill gaps surfaced by developer feedback#563
localden wants to merge 8 commits intomainfrom
docs/fill-gaps-from-feedback

Conversation

@localden
Copy link
Copy Markdown
Contributor

Summary

Adds documentation for recurring questions and pitfalls that surfaced while building real Apps:

  • patterns.md — new sections on model-vs-App data visibility, height control (and the autoResize + 100vh loop), touch device support, localStorage namespacing, sharing one ui:// resource across tools, conditionally showing UI, openLink, and the color-scheme iframe transparency gotcha
  • overview.md — note on resource versioning/caching (template and tool result may come from different code versions)
  • New pagesdesign-guidelines.md and troubleshooting.md, wired into typedoc.config.mjs

Test plan

  • npm exec typedoc -- --treatValidationWarningsAsErrors --emit none passes
  • npm run build generates docs without broken {@link} references
  • New pages render correctly in the TypeDoc sidebar
  • Internal anchor links in patterns.md resolve

Adds guidance for recurring questions and pitfalls that came up while
building Apps against the SDK:

patterns.md:
- Model vs App data visibility (content/structuredContent/_meta split)
- Controlling App height, including the autoResize + 100vh feedback loop
- Touch device support (touch-action, horizontal overflow)
- localStorage key namespacing across shared sandbox origin
- Sharing a single ui:// resource across multiple tools
- Conditionally showing UI (two-tool workaround)
- Opening external links via app.openLink
- color-scheme CSS gotcha that breaks iframe transparency

overview.md:
- Resource versioning/caching note — template and data may be from
  different code versions

New pages:
- design-guidelines.md
- troubleshooting.md

typedoc.config.mjs wired up to include the two new pages.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 23, 2026

📖 Docs Preview Deployed

Preview (stable) https://pr-563.mcp-ext-apps-docs-preview.pages.dev
This commit https://a3e6887c.mcp-ext-apps-docs-preview.pages.dev
Commit 550eee4

Includes drafts and future-dated posts. All pages served with noindex, nofollow — search engines will not crawl this preview.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 23, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@563

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@563

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@563

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@563

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@563

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@563

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@563

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@563

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@563

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@563

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@563

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@563

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@563

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@563

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@563

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@563

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@563

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@563

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@563

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@563

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@563

commit: 7486dee

@localden localden added the documentation Improvements or additions to documentation label Mar 23, 2026
Copy link
Copy Markdown
Contributor

@ochafik ochafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @localden !

Comment thread docs/design-guidelines.md Outdated

An MCP App answers one question or supports one task. Avoid building a full dashboard with tabs, sidebars, and settings panels.

- Inline mode should fit within roughly one viewport of scroll. Content that is significantly taller than the chat viewport belongs in fullscreen mode, or should be trimmed.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one. I think it's fine to have longer apps, as long as they don't have nested scrolling in inline mode (big no-no).

Comment thread docs/design-guidelines.md Outdated
An MCP App answers one question or supports one task. Avoid building a full dashboard with tabs, sidebars, and settings panels.

- Inline mode should fit within roughly one viewport of scroll. Content that is significantly taller than the chat viewport belongs in fullscreen mode, or should be trimmed.
- Limit inline mode to one primary action. A "Confirm" button is appropriate; a toolbar with eight icons is not.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain the intent behind this rather than the arbitrary limitation to achieve it? (if it's because inline chats may have limited space and a toolbar would be a bit cramped, maybe emphasize the fact the app layout should be progressive / cater to small widths, and be mobile friendly?

Comment thread docs/design-guidelines.md Outdated

- Inline mode should fit within roughly one viewport of scroll. Content that is significantly taller than the chat viewport belongs in fullscreen mode, or should be trimmed.
- Limit inline mode to one primary action. A "Confirm" button is appropriate; a toolbar with eight icons is not.
- Let the conversation handle navigation. Rather than adding a search box inside the App, let the user ask a follow-up question that re-invokes the tool with new arguments.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Counter example: Ctrl+F in PDF-viewer. And its interact pattern or upcoming #72 primitive to invoke search programmatically on an existing component.

I'd focus on discouraging multipage navigation in inline mode (might be okay in fullscreen).

Comment thread docs/design-guidelines.md Outdated

## Host UI imitation

Your App must not resemble the surrounding chat client. Do not render:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly at odds w/ encouraging apps to use native styles, font and colors. Maybe reformulate as avoid confusion between the app and the surrounding chat.

Comment thread docs/design-guidelines.md Outdated

## Display modes

Design for inline mode first. It is the default, and it is narrow (often the width of a chat message) and height-constrained.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline isn't height-constrained (or we constrain it to like 6000px, on purpose).

Comment thread docs/patterns.md Outdated
> [!WARNING]
> Do not combine `autoResize: true` with `height: 100vh` or `100%` on the root element. The SDK reports the document height, the host grows the iframe to match, the document sees a taller viewport and grows again. This loops until the host's maximum height cap.

The React `useApp` hook always creates the App with `autoResize: true`. For fixed or host-driven height, construct the `App` manually or use the `useAutoResize` hook with a specific element.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The React useApp hook always creates the App with `autoResize: true

we should fix this btw 🙈

Comment thread docs/patterns.md

## Conditionally showing UI

The tool-to-resource binding is declared at registration time. A tool either has a `_meta.ui.resourceUri` or it does not; the server cannot decide per-call whether to render UI.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the server cannot decide

Stateful servers can decide to register different tools based on the initialize capabilities if the MCP Apps extension is declared (cf. getUiCapability helper in /server)

Comment thread docs/patterns.md Outdated

If the decision must be made server-side (for example, showing UI only when the result set exceeds a threshold), the workaround is to always attach the UI resource and have the App render a minimal collapsed placeholder when there is nothing to show. Keep the placeholder small to avoid adding visual noise to the conversation.

## Opening external links
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe also mention downloadFile, and capability fencing for both

Comment thread docs/troubleshooting.md

# Troubleshooting

## Blank iframe
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failure to call connect is my own most frequent cause for this (esp. if iframe has zero size)

Comment thread docs/troubleshooting.md Outdated

MCP Apps are portable only if they use the SDK exclusively. Common portability mistakes:

- **Host-specific globals.** Do not reference `window.openai`, `window.claude`, or any other host-injected object. Use the `App` class from this SDK, which speaks the standard protocol to any compliant host.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about mentioning hypothetical window.claude?

localden and others added 6 commits April 17, 2026 17:01
…shooting

- design-guidelines: reframe scope bullets around no-nested-scroll / narrow-width
  layout / no multi-page nav; clarify host-UI imitation vs native styling tension;
  drop "height-constrained" inline claim; point to containerDimensions via
  onhostcontextchanged; note App mounts before tool inputs are sent
- patterns: correct structuredContent model-visibility (shown iff content empty);
  rework touch-action guidance so inline never blocks vertical scroll; add
  sendSizeChanged to fixed-height recipe; document getUiCapability for per-client
  tool registration; add downloadFile + capability fencing alongside openLink
- troubleshooting: lead blank-iframe list with missing connect(); drop
  hypothetical window.claude reference
Accuracy:
- patterns: drop incorrect useAutoResize-with-element advice; useApp simply
  doesn't expose autoResize, so construct App manually
- patterns: add full host-driven height snippet using addEventListener and
  the containerDimensions union (with in-guards), plus a strategy decision table
- patterns/overview: align structuredContent visibility wording (model sees it
  only when content is empty) across both pages
- design-guidelines/patterns/troubleshooting: switch new content from deprecated
  on* setters to addEventListener; retitle troubleshooting section to event names
- design-guidelines: describe containerDimensions as fixed-or-max bounds, not
  plain {width,height}

Gaps:
- design-guidelines: cover toolcancelled as a terminal loading state; mention
  requestTeardown alongside the no-close-button guidance
- troubleshooting: surface basic-host repro tip at top of Blank iframe

Clarity/examples:
- patterns: openLink/downloadFile snippet now gates control rendering, not the
  call site; sharing-one-UI snippet guards isError before casting; fixed-height
  snippet uses bare app.connect(); dedupe 100vh warning
- design-guidelines: reword Scope intro to target application shells (resolve
  tabs contradiction); soften inline-height claim and cross-link to patterns
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants